// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "cc/trees/layer_tree_host.h"

#include "cc/test/fake_content_layer_client.h"
#include "cc/test/fake_picture_layer.h"
#include "cc/test/fake_picture_layer_impl.h"
#include "cc/test/layer_tree_test.h"
#include "cc/trees/layer_tree_impl.h"

namespace cc {
namespace {

    // These tests deal with picture layers.
    class LayerTreeHostPictureTest : public LayerTreeTest {
    protected:
        void SetupTreeWithSinglePictureLayer(const gfx::Size& size)
        {
            scoped_refptr<Layer> root = Layer::Create();
            root->SetBounds(size);

            root_picture_layer_ = FakePictureLayer::Create(&client_);
            root_picture_layer_->SetBounds(size);
            root->AddChild(root_picture_layer_);

            layer_tree()->SetRootLayer(root);
            client_.set_bounds(size);
        }

        scoped_refptr<FakePictureLayer> root_picture_layer_;
        FakeContentLayerClient client_;
    };

    class LayerTreeHostPictureTestTwinLayer
        : public LayerTreeHostPictureTest {
        void SetupTree() override
        {
            SetupTreeWithSinglePictureLayer(gfx::Size(1, 1));
            picture_id1_ = root_picture_layer_->id();
            picture_id2_ = -1;
        }

        void BeginTest() override
        {
            activates_ = 0;
            PostSetNeedsCommitToMainThread();
        }

        void DidCommit() override
        {
            switch (layer_tree_host()->SourceFrameNumber()) {
            case 1:
                // Activate while there are pending and active twins in place.
                layer_tree_host()->SetNeedsCommit();
                break;
            case 2:
                // Drop the picture layer from the tree so the activate will have an
                // active layer without a pending twin.
                root_picture_layer_->RemoveFromParent();
                break;
            case 3: {
                // Add a new picture layer so the activate will have a pending layer
                // without an active twin.
                scoped_refptr<FakePictureLayer> picture = FakePictureLayer::Create(&client_);
                picture_id2_ = picture->id();
                layer_tree()->root_layer()->AddChild(picture);
                break;
            }
            case 4:
                // Active while there are pending and active twins again.
                layer_tree_host()->SetNeedsCommit();
                break;
            case 5:
                EndTest();
                break;
            }
        }

        void WillActivateTreeOnThread(LayerTreeHostImpl* impl) override
        {
            LayerImpl* active_root_impl = impl->active_tree()->root_layer_for_testing();
            int picture_id = impl->active_tree()->source_frame_number() < 2
                ? picture_id1_
                : picture_id2_;

            if (!impl->pending_tree()->LayerById(picture_id)) {
                EXPECT_EQ(2, activates_);
                return;
            }

            FakePictureLayerImpl* pending_picture_impl = static_cast<FakePictureLayerImpl*>(
                impl->pending_tree()->LayerById(picture_id));

            if (!active_root_impl) {
                EXPECT_EQ(0, activates_);
                EXPECT_EQ(nullptr, pending_picture_impl->GetPendingOrActiveTwinLayer());
                return;
            }

            if (!impl->active_tree()->LayerById(picture_id)) {
                EXPECT_EQ(3, activates_);
                EXPECT_EQ(nullptr, pending_picture_impl->GetPendingOrActiveTwinLayer());
                return;
            }

            FakePictureLayerImpl* active_picture_impl = static_cast<FakePictureLayerImpl*>(
                impl->active_tree()->LayerById(picture_id));

            // After the first activation, when we commit again, we'll have a pending
            // and active layer. Then we recreate a picture layer in the 4th activate
            // and the next commit will have a pending and active twin again.
            EXPECT_TRUE(activates_ == 1 || activates_ == 4) << activates_;

            EXPECT_EQ(pending_picture_impl,
                active_picture_impl->GetPendingOrActiveTwinLayer());
            EXPECT_EQ(active_picture_impl,
                pending_picture_impl->GetPendingOrActiveTwinLayer());
        }

        void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override
        {
            int picture_id = impl->active_tree()->source_frame_number() < 3
                ? picture_id1_
                : picture_id2_;
            if (!impl->active_tree()->LayerById(picture_id)) {
                EXPECT_EQ(2, activates_);
            } else {
                FakePictureLayerImpl* active_picture_impl = static_cast<FakePictureLayerImpl*>(
                    impl->active_tree()->LayerById(picture_id));
                EXPECT_EQ(nullptr, active_picture_impl->GetPendingOrActiveTwinLayer());
            }

            ++activates_;
        }

        void AfterTest() override { EXPECT_EQ(5, activates_); }

        int activates_;
        int picture_id1_;
        int picture_id2_;
    };

    // There is no pending layers in single thread mode.
    MULTI_THREAD_TEST_F(LayerTreeHostPictureTestTwinLayer);

    class LayerTreeHostPictureTestResizeViewportWithGpuRaster
        : public LayerTreeHostPictureTest {
        void InitializeSettings(LayerTreeSettings* settings) override
        {
            settings->gpu_rasterization_forced = true;
        }

        void SetupTree() override
        {
            scoped_refptr<Layer> root = Layer::Create();
            root->SetBounds(gfx::Size(768, 960));
            client_.set_bounds(root->bounds());
            client_.set_fill_with_nonsolid_color(true);
            picture_ = FakePictureLayer::Create(&client_);
            picture_->SetBounds(gfx::Size(768, 960));
            root->AddChild(picture_);

            layer_tree()->SetRootLayer(root);
            LayerTreeHostPictureTest::SetupTree();
        }

        void BeginTest() override { PostSetNeedsCommitToMainThread(); }

        void CommitCompleteOnThread(LayerTreeHostImpl* impl) override
        {
            LayerImpl* child = impl->sync_tree()->LayerById(picture_->id());
            FakePictureLayerImpl* picture_impl = static_cast<FakePictureLayerImpl*>(child);
            gfx::Size tile_size = picture_impl->HighResTiling()->TileAt(0, 0)->content_rect().size();

            switch (impl->sync_tree()->source_frame_number()) {
            case 0:
                tile_size_ = tile_size;
                // GPU Raster picks a tile size based on the viewport size.
                EXPECT_EQ(gfx::Size(768, 256), tile_size);
                break;
            case 1:
                // When the viewport changed size, the new frame's tiles should change
                // along with it.
                EXPECT_NE(gfx::Size(768, 256), tile_size);
            }
        }

        void DidCommit() override
        {
            switch (layer_tree_host()->SourceFrameNumber()) {
            case 1:
                // Change the picture layer's size along with the viewport, so it will
                // consider picking a new tile size.
                picture_->SetBounds(gfx::Size(768, 1056));
                layer_tree()->SetViewportSize(gfx::Size(768, 1056));
                break;
            case 2:
                EndTest();
            }
        }

        void AfterTest() override { }

        gfx::Size tile_size_;
        FakeContentLayerClient client_;
        scoped_refptr<FakePictureLayer> picture_;
    };

    SINGLE_AND_MULTI_THREAD_TEST_F(
        LayerTreeHostPictureTestResizeViewportWithGpuRaster);

    class LayerTreeHostPictureTestChangeLiveTilesRectWithRecycleTree
        : public LayerTreeHostPictureTest {
        void SetupTree() override
        {
            frame_ = 0;
            did_post_commit_ = false;

            scoped_refptr<Layer> root = Layer::Create();
            root->SetBounds(gfx::Size(100, 100));
            // The layer is big enough that the live tiles rect won't cover the full
            // layer.
            client_.set_fill_with_nonsolid_color(true);
            picture_ = FakePictureLayer::Create(&client_);
            picture_->SetBounds(gfx::Size(100, 100000));
            root->AddChild(picture_);

            // picture_'s transform is going to be changing on the compositor thread, so
            // force it to have a transform node by making it scrollable.
            picture_->SetScrollClipLayerId(root->id());

            layer_tree()->SetRootLayer(root);
            LayerTreeHostPictureTest::SetupTree();
            client_.set_bounds(picture_->bounds());
        }

        void BeginTest() override { PostSetNeedsCommitToMainThread(); }

        void DrawLayersOnThread(LayerTreeHostImpl* impl) override
        {
            LayerImpl* child = impl->active_tree()->LayerById(picture_->id());
            FakePictureLayerImpl* picture_impl = static_cast<FakePictureLayerImpl*>(child);
            switch (++frame_) {
            case 1: {
                PictureLayerTiling* tiling = picture_impl->HighResTiling();
                int num_tiles_y = tiling->TilingDataForTesting().num_tiles_y();

                // There should be tiles at the top of the picture layer but not at the
                // bottom.
                EXPECT_TRUE(tiling->TileAt(0, 0));
                EXPECT_FALSE(tiling->TileAt(0, num_tiles_y));

                // Make the bottom of the layer visible.
                gfx::Transform transform;
                transform.Translate(0.f, -100000.f + 100.f);
                impl->active_tree()
                    ->property_trees()
                    ->transform_tree.OnTransformAnimated(
                        transform, picture_impl->transform_tree_index(),
                        impl->active_tree());
                impl->SetNeedsRedraw();
                break;
            }
            case 2: {
                PictureLayerTiling* tiling = picture_impl->HighResTiling();

                // There not be tiles at the top of the layer now.
                EXPECT_FALSE(tiling->TileAt(0, 0));

                // Make the top of the layer visible again.
                impl->active_tree()
                    ->property_trees()
                    ->transform_tree.OnTransformAnimated(
                        gfx::Transform(), picture_impl->transform_tree_index(),
                        impl->active_tree());
                impl->SetNeedsRedraw();
                break;
            }
            case 3: {
                PictureLayerTiling* tiling = picture_impl->HighResTiling();
                int num_tiles_y = tiling->TilingDataForTesting().num_tiles_y();

                // There should be tiles at the top of the picture layer again.
                EXPECT_TRUE(tiling->TileAt(0, 0));
                EXPECT_FALSE(tiling->TileAt(0, num_tiles_y));

                // Make a new main frame without changing the picture layer at all, so
                // it won't need to update or push properties.
                did_post_commit_ = true;
                PostSetNeedsCommitToMainThread();
                break;
            }
            }
        }

        void WillActivateTreeOnThread(LayerTreeHostImpl* impl) override
        {
            LayerImpl* child = impl->sync_tree()->LayerById(picture_->id());
            FakePictureLayerImpl* picture_impl = static_cast<FakePictureLayerImpl*>(child);
            PictureLayerTiling* tiling = picture_impl->HighResTiling();
            int num_tiles_y = tiling->TilingDataForTesting().num_tiles_y();

            if (!impl->active_tree()->root_layer_for_testing()) {
                // If active tree doesn't have the layer, then pending tree should have
                // all needed tiles.
                EXPECT_TRUE(tiling->TileAt(0, 0));
            } else {
                // Since there was no invalidation, the pending tree shouldn't have any
                // tiles.
                EXPECT_FALSE(tiling->TileAt(0, 0));
            }
            EXPECT_FALSE(tiling->TileAt(0, num_tiles_y));

            if (did_post_commit_)
                EndTest();
        }

        void AfterTest() override { }

        int frame_;
        bool did_post_commit_;
        FakeContentLayerClient client_;
        scoped_refptr<FakePictureLayer> picture_;
    };

    // Multi-thread only since there is no recycle tree in single thread.
    MULTI_THREAD_TEST_F(LayerTreeHostPictureTestChangeLiveTilesRectWithRecycleTree);

    class LayerTreeHostPictureTestRSLLMembership : public LayerTreeHostPictureTest {
        void SetupTree() override
        {
            scoped_refptr<Layer> root = Layer::Create();
            root->SetBounds(gfx::Size(100, 100));
            client_.set_bounds(root->bounds());

            child_ = Layer::Create();
            root->AddChild(child_);

            // Don't be solid color so the layer has tilings/tiles.
            client_.set_fill_with_nonsolid_color(true);
            picture_ = FakePictureLayer::Create(&client_);
            picture_->SetBounds(gfx::Size(100, 100));
            child_->AddChild(picture_);

            layer_tree()->SetRootLayer(root);
            LayerTreeHostPictureTest::SetupTree();
        }

        void BeginTest() override { PostSetNeedsCommitToMainThread(); }

        void CommitCompleteOnThread(LayerTreeHostImpl* impl) override
        {
            LayerImpl* gchild = impl->sync_tree()->LayerById(picture_->id());
            FakePictureLayerImpl* picture = static_cast<FakePictureLayerImpl*>(gchild);

            switch (impl->sync_tree()->source_frame_number()) {
            case 0:
                // On 1st commit the layer has tilings.
                EXPECT_GT(picture->tilings()->num_tilings(), 0u);
                break;
            case 1:
                // On 2nd commit, the layer is transparent, but its tilings are left
                // there.
                EXPECT_GT(picture->tilings()->num_tilings(), 0u);
                break;
            case 2:
                // On 3rd commit, the layer is visible again, so has tilings.
                EXPECT_GT(picture->tilings()->num_tilings(), 0u);
            }
        }

        void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override
        {
            LayerImpl* gchild = impl->sync_tree()->LayerById(picture_->id());
            FakePictureLayerImpl* picture = static_cast<FakePictureLayerImpl*>(gchild);

            switch (impl->active_tree()->source_frame_number()) {
            case 0:
                // On 1st commit the layer has tilings.
                EXPECT_GT(picture->tilings()->num_tilings(), 0u);
                break;
            case 1:
                // On 2nd commit, the layer is transparent, but its tilings are left
                // there.
                EXPECT_GT(picture->tilings()->num_tilings(), 0u);
                break;
            case 2:
                // On 3rd commit, the layer is visible again, so has tilings.
                EXPECT_GT(picture->tilings()->num_tilings(), 0u);
                EndTest();
            }
        }

        void DidCommit() override
        {
            switch (layer_tree_host()->SourceFrameNumber()) {
            case 1:
                // For the 2nd commit, change opacity to 0 so that the layer will not be
                // part of the visible frame.
                child_->SetOpacity(0.f);
                break;
            case 2:
                // For the 3rd commit, change opacity to 1 so that the layer will again
                // be part of the visible frame.
                child_->SetOpacity(1.f);
            }
        }

        void AfterTest() override { }

        FakeContentLayerClient client_;
        scoped_refptr<Layer> child_;
        scoped_refptr<FakePictureLayer> picture_;
    };

    SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostPictureTestRSLLMembership);

    class LayerTreeHostPictureTestRSLLMembershipWithScale
        : public LayerTreeHostPictureTest {
        void SetupTree() override
        {
            scoped_refptr<Layer> root_clip = Layer::Create();
            root_clip->SetBounds(gfx::Size(100, 100));
            scoped_refptr<Layer> page_scale_layer = Layer::Create();
            page_scale_layer->SetBounds(gfx::Size(100, 100));

            pinch_ = Layer::Create();
            pinch_->SetBounds(gfx::Size(500, 500));
            pinch_->SetScrollClipLayerId(root_clip->id());
            pinch_->SetIsContainerForFixedPositionLayers(true);
            page_scale_layer->AddChild(pinch_);
            root_clip->AddChild(page_scale_layer);

            // Don't be solid color so the layer has tilings/tiles.
            client_.set_fill_with_nonsolid_color(true);
            picture_ = FakePictureLayer::Create(&client_);
            picture_->SetBounds(gfx::Size(100, 100));
            pinch_->AddChild(picture_);

            layer_tree()->RegisterViewportLayers(NULL, page_scale_layer, pinch_,
                nullptr);
            layer_tree()->SetPageScaleFactorAndLimits(1.f, 1.f, 4.f);
            layer_tree()->SetRootLayer(root_clip);
            LayerTreeHostPictureTest::SetupTree();
            client_.set_bounds(picture_->bounds());
        }

        void InitializeSettings(LayerTreeSettings* settings) override
        {
            settings->layer_transforms_should_scale_layer_contents = true;
        }

        void BeginTest() override
        {
            frame_ = 0;
            draws_in_frame_ = 0;
            last_frame_drawn_ = -1;
            ready_to_draw_ = false;
            PostSetNeedsCommitToMainThread();
        }

        void WillActivateTreeOnThread(LayerTreeHostImpl* impl) override
        {
            LayerImpl* gchild = impl->sync_tree()->LayerById(picture_->id());
            FakePictureLayerImpl* picture = static_cast<FakePictureLayerImpl*>(gchild);
            ready_to_draw_ = false;

            switch (frame_) {
            case 0:
                // On 1st commit the pending layer has tilings.
                ASSERT_EQ(1u, picture->tilings()->num_tilings());
                EXPECT_EQ(1.f, picture->tilings()->tiling_at(0)->contents_scale());
                break;
            case 1:
                // On 2nd commit, the pending layer is transparent, so has a stale
                // value.
                ASSERT_EQ(1u, picture->tilings()->num_tilings());
                EXPECT_EQ(1.f, picture->tilings()->tiling_at(0)->contents_scale());
                break;
            case 2:
                // On 3rd commit, the pending layer is visible again, so has tilings and
                // is updated for the pinch.
                ASSERT_EQ(1u, picture->tilings()->num_tilings());
                EXPECT_EQ(2.f, picture->tilings()->tiling_at(0)->contents_scale());
            }
        }

        void DrawLayersOnThread(LayerTreeHostImpl* impl) override
        {
            LayerImpl* gchild = impl->active_tree()->LayerById(picture_->id());
            FakePictureLayerImpl* picture = static_cast<FakePictureLayerImpl*>(gchild);

            if (frame_ != last_frame_drawn_)
                draws_in_frame_ = 0;
            ++draws_in_frame_;
            last_frame_drawn_ = frame_;

            switch (frame_) {
            case 0:
                if (draws_in_frame_ == 1) {
                    // On 1st commit the layer has tilings.
                    EXPECT_GT(picture->tilings()->num_tilings(), 0u);
                    EXPECT_EQ(1.f, picture->HighResTiling()->contents_scale());

                    // Pinch zoom in to change the scale on the active tree.
                    impl->PinchGestureBegin();
                    impl->PinchGestureUpdate(2.f, gfx::Point(1, 1));
                    impl->PinchGestureEnd();
                } else if (picture->tilings()->num_tilings() == 1) {
                    // If the pinch gesture caused a commit we could get here with a
                    // pending tree.
                    EXPECT_FALSE(impl->pending_tree());
                    EXPECT_EQ(2.f, picture->HighResTiling()->contents_scale());

                    // Need to wait for ready to draw here so that the pinch is
                    // entirely complete, otherwise another draw might come in before
                    // the commit occurs.
                    if (ready_to_draw_) {
                        ++frame_;
                        MainThreadTaskRunner()->PostTask(
                            FROM_HERE,
                            base::Bind(
                                &LayerTreeHostPictureTestRSLLMembershipWithScale::NextStep,
                                base::Unretained(this)));
                    }
                }
                break;
            case 1:
                EXPECT_EQ(1, draws_in_frame_);
                // On 2nd commit, this active layer is transparent, so does not update
                // tilings.  It has the high res scale=2 from the previous frame, and
                // also a scale=1 copied from the pending layer's stale value during
                // activation.
                EXPECT_EQ(2u, picture->picture_layer_tiling_set()->num_tilings());

                ++frame_;
                MainThreadTaskRunner()->PostTask(
                    FROM_HERE,
                    base::Bind(
                        &LayerTreeHostPictureTestRSLLMembershipWithScale::NextStep,
                        base::Unretained(this)));
                break;
            case 2:
                EXPECT_EQ(1, draws_in_frame_);
                // On 3rd commit, the layer is visible again, so has tilings.
                EXPECT_GT(picture->tilings()->num_tilings(), 0u);
                EndTest();
            }
        }

        void NextStep()
        {
            switch (frame_) {
            case 1:
                // For the 2nd commit, change opacity to 0 so that the layer will not be
                // part of the visible frame.
                pinch_->SetOpacity(0.f);
                break;
            case 2:
                // For the 3rd commit, change opacity to 1 so that the layer will again
                // be part of the visible frame.
                pinch_->SetOpacity(1.f);
                break;
            }
        }

        void NotifyReadyToDrawOnThread(LayerTreeHostImpl* impl) override
        {
            ready_to_draw_ = true;
            if (frame_ == 0) {
                // The ready to draw can race with a draw in which everything is
                // actually ready.  Therefore, just issue one more extra draw
                // here to force notify->draw ordering.
                impl->SetNeedsRedraw();
            }
        }

        void AfterTest() override { }

        FakeContentLayerClient client_;
        scoped_refptr<Layer> pinch_;
        scoped_refptr<FakePictureLayer> picture_;
        int frame_;
        int draws_in_frame_;
        int last_frame_drawn_;
        bool ready_to_draw_;
    };

    // Multi-thread only because in single thread you can't pinch zoom on the
    // compositor thread.
    MULTI_THREAD_TEST_F(LayerTreeHostPictureTestRSLLMembershipWithScale);

    class LayerTreeHostPictureTestForceRecalculateScales
        : public LayerTreeHostPictureTest {
        void SetupTree() override
        {
            gfx::Size size(100, 100);
            scoped_refptr<Layer> root = Layer::Create();
            root->SetBounds(size);

            will_change_layer_ = FakePictureLayer::Create(&client_);
            will_change_layer_->SetHasWillChangeTransformHint(true);
            will_change_layer_->SetBounds(size);
            root->AddChild(will_change_layer_);

            normal_layer_ = FakePictureLayer::Create(&client_);
            normal_layer_->SetBounds(size);
            root->AddChild(normal_layer_);

            layer_tree()->SetRootLayer(root);
            layer_tree()->SetViewportSize(size);

            client_.set_fill_with_nonsolid_color(true);
            client_.set_bounds(size);
        }

        void InitializeSettings(LayerTreeSettings* settings) override
        {
            settings->layer_transforms_should_scale_layer_contents = true;
        }

        void BeginTest() override { PostSetNeedsCommitToMainThread(); }

        void DrawLayersOnThread(LayerTreeHostImpl* impl) override
        {
            FakePictureLayerImpl* will_change_layer = static_cast<FakePictureLayerImpl*>(
                impl->active_tree()->LayerById(will_change_layer_->id()));
            FakePictureLayerImpl* normal_layer = static_cast<FakePictureLayerImpl*>(
                impl->active_tree()->LayerById(normal_layer_->id()));

            switch (impl->sync_tree()->source_frame_number()) {
            case 0:
                // On first commit, both layers are at the default scale.
                ASSERT_EQ(1u, will_change_layer->tilings()->num_tilings());
                EXPECT_EQ(1.f,
                    will_change_layer->tilings()->tiling_at(0)->contents_scale());
                ASSERT_EQ(1u, normal_layer->tilings()->num_tilings());
                EXPECT_EQ(1.f, normal_layer->tilings()->tiling_at(0)->contents_scale());

                MainThreadTaskRunner()->PostTask(
                    FROM_HERE,
                    base::Bind(
                        &LayerTreeHostPictureTestForceRecalculateScales::ScaleRootUp,
                        base::Unretained(this)));
                break;
            case 1:
                // On 2nd commit after scaling up to 2, the normal layer will adjust its
                // scale and the will change layer should not (as it is will change.
                ASSERT_EQ(1u, will_change_layer->tilings()->num_tilings());
                EXPECT_EQ(1.f,
                    will_change_layer->tilings()->tiling_at(0)->contents_scale());
                ASSERT_EQ(1u, normal_layer->tilings()->num_tilings());
                EXPECT_EQ(2.f, normal_layer->tilings()->tiling_at(0)->contents_scale());

                MainThreadTaskRunner()->PostTask(
                    FROM_HERE,
                    base::Bind(&LayerTreeHostPictureTestForceRecalculateScales::
                                   ScaleRootUpAndRecalculateScales,
                        base::Unretained(this)));
                break;
            case 2:
                // On 3rd commit, both layers should adjust scales due to forced
                // recalculating.
                ASSERT_EQ(1u, will_change_layer->tilings()->num_tilings());
                EXPECT_EQ(4.f,
                    will_change_layer->tilings()->tiling_at(0)->contents_scale());
                ASSERT_EQ(1u, normal_layer->tilings()->num_tilings());
                EXPECT_EQ(4.f, normal_layer->tilings()->tiling_at(0)->contents_scale());
                EndTest();
                break;
            }
        }

        void ScaleRootUp()
        {
            gfx::Transform transform;
            transform.Scale(2, 2);
            layer_tree_host()->GetLayerTree()->root_layer()->SetTransform(transform);
        }

        void ScaleRootUpAndRecalculateScales()
        {
            gfx::Transform transform;
            transform.Scale(4, 4);
            layer_tree_host()->GetLayerTree()->root_layer()->SetTransform(transform);
            layer_tree_host()->SetNeedsRecalculateRasterScales();
        }

        void AfterTest() override { }

        scoped_refptr<FakePictureLayer> will_change_layer_;
        scoped_refptr<FakePictureLayer> normal_layer_;
    };

    SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostPictureTestForceRecalculateScales);

} // namespace
} // namespace cc
